//
// Created by tang on 2020/6/19.
//

#include "utility.hpp"
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>
#include <vector>
#include <cmath>

std::string getSelfExecutablePath() {
    constexpr size_t max_path = 1024;
    char buff[max_path];
    int len = readlink("/proc/self/exe", buff, max_path);
    if (len != -1)
    {
        return {buff, static_cast<size_t>(len)};
    }
    return "";
}

double getCPULoadAverage() {
    double numbers[3];
    int r = getloadavg(numbers, 3);
    if (r < 0)
    {
        return 0.0;
    }
    else
    {
        return std::min(numbers[0], 4.0) / 4;
    }
}

std::string getBootTime() {
    int fd = open("/proc/stat", O_RDONLY);
    if (0 > fd)
        return "N/A";

    // read /proc/stat file
    std::vector<char> buffer(4096);
    int size = read(fd, buffer.data(), buffer.size());
    close(fd);
    if (size <= 0)
        return "N/A";

    // parse
    std::string txt(buffer.data(), size);
    size_t start = txt.rfind("btime") + sizeof("btime");
    size_t end = txt.find('\n', start);

    // convert
    time_t boot_time = std::stol(txt.substr(start, end - start));
    struct tm local_tm{};
    if (localtime_r(&boot_time, &local_tm) != &local_tm)
        return "Err";
    size = strftime(buffer.data(), buffer.size(), "%d/%m  %H:%M:%S", &local_tm);

    return std::string(buffer.data(), size);
}

std::string getUptime() {
    int fd = open("/proc/uptime", O_RDONLY);
    if (0 > fd)
        return "N/A";

    // read /proc/uptime file
    std::vector<char> buffer(1024);
    int size = read(fd, buffer.data(), buffer.size());
    close(fd);
    if (size <= 0)
        return "N/A";

    // parse
    std::string txt(buffer.data(), size);
    size_t split = txt.find(' ');
    double seconds = std::stod(txt.substr(0, split));

    // build time
    size = sprintf(buffer.data(), "%lld:%02lld:%02lld",
                   static_cast<long long>(seconds)/3600, // hour
                   static_cast<long long>(seconds)%3600/60, // minute
                   static_cast<long long>(seconds)%60 // second
                   );
    if (size <= 0)
        return "N/A";
    return std::string(buffer.data(), size);
}
